﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using Services;

namespace Logic
{
    public class HtmlChecker : IHtmlChecker
    {
        public string LookAhead(string html, int start, out bool isClose, out bool isSolo)
        {
            isClose = false;
            isSolo = false;

            var tagName = new StringBuilder();
            int slashPos = -1;
            bool space = false;
            bool quote = false;

            int i;
            for (i = 0; ; i++)
            {

                int pos = start + i;
                if (pos >= html.Length)
                {
                    return "x";
                }

                char c = html[pos];
                //пробел
                if (char.IsWhiteSpace(c))
                {
                    space = true;
                }

                if (space == false &&
                    c != '<' &&
                    c != '>' &&
                    c != '/')
                {
                    tagName.Append(c);
                }

                if (c == '/' &&
                    quote == false)
                {
                    slashPos = i;
                }

                if (c == '>')
                {
                    break;
                }

                if (c == '\"')
                {
                    quote = !quote;
                }
            }


            if (slashPos != -1)
            {

                if (slashPos + 1 == i)
                {
                    isSolo = true;
                }
                else
                {
                    isClose = true;
                }
            }

            string name = tagName.ToString();
            if (name.Length == 0)
            {
                return "empty";
            }
            else
            {
                return name;
            }
        }

        static readonly Dictionary<string, bool> SoloTags = new Dictionary<string, bool>()
{
    {"img", true},
    {"br", true}
};


        public void CheckHtml(string html, out string error)
        {
            var tags = new Stack<string>();
            error = string.Empty;
            int parenthesisR = 0;
            int parenthesisL = 0;
            for (int i = 0; i < html.Length; i++)
            {
                char c = html[i];
                if (c == '<')
                {
                    bool isClose;
                    bool isSolo;
                    string tag = LookAhead(html, i, out isClose, out isSolo);
                    if (tag.ToLower() != tag)
                    {
                        error = "upper: " + tag;
                        return;
                    }

                    if (SoloTags.ContainsKey(tag))
                    {
                        if (!isSolo)
                        {
                            error = "!solo: " + tag;
                            return;
                        }
                    }
                    else
                    {

                        if (isClose)
                        {

                            if (tags.Count == 0)
                            {
                                error = "closing: " + tag;
                                return;
                            }

                            if (tags.Peek() == tag)
                            {
                                tags.Pop();
                            }
                            else
                            {
                                error = "!match: " + tag;
                                return;
                            }
                        }
                        else
                        {
                            tags.Push(tag);
                        }
                    }
                    i += tag.Length;
                }
                else if (c == '&')
                {
                    if ((i + 1) < html.Length)
                    {
                        char next = html[i + 1];

                        if (char.IsWhiteSpace(next) ||
                            next == '&')
                        {
                            error = "ampersand";
                            return;
                        }
                    }
                }
                else if (c == '\t')
                {
                    error = "tab";
                    return;
                }
                else if (c == '(')
                {
                    parenthesisL++;
                }
                else if (c == ')')
                {
                    parenthesisR++;
                }
            }

            error = tags.Aggregate(error, (current, tagName) => current + ("extra:" + tagName + " "));
            if (parenthesisL != parenthesisR)
            {
                error = "!even ";
            }
        }
    }
}